
#include "processor.h"

#ifdef Task_1
// Constructor
Processor::Processor(sc_module_name processor_name) : sc_module (processor_name)
{
  //lol
	unique = -1; // Indicates that number has not yet been found.
	busy = false;
	SC_HAS_PROCESS(Processor);
	SC_THREAD(main);
	//cout << name() << " constructor lol" << endl;
}

/* Processor::free(void) is used to check if the processor is busy with requests from other
 * Specifically if the processor is currently answering a test(x) from another processor,
 * or have not found it's own unique value yet.
*/
bool Processor::free(void)
{
	// try to lock testMutex
	// if yes return true
  //if (test_mutex.trylock() == 0){
  //test_mutex.unlock();
    return !busy;
    //}
    //return false;
}

// Returns true if n is found to be in use, and false if n appears to be available.
bool Processor::test(int n, bool up)
{
	// Lock testMutex
	//test_mutex.lock(); // This should wait if bus is occupied.
	busy = true;
	bool temp;
	// Perform test:
		// Check if number is my unique number.
		// TODO: Should be combined with vector.
		/*if(n == this->unique)
		{
			test_mutex.unlock();
			free_var = true;
 			return false;
			}*/
		// Check if n is any of the known numbers_in_use.
		for(std::vector<int>::iterator it = numbers_in_use.begin(); it!=numbers_in_use.end();++it)
		{
			if(*it == n)
			  {
			    //test_mutex.unlock();
				busy=false;
				return false;
			}
		}
		// Ask if neighbours know anything about n
		// TODO: Should check if they are free first.
		numbers_in_use.push_back(n);
		if (up){
		while (!upp->free()) wait(SC_ZERO_TIME);
		temp = upp -> test(n, 1);
		}
		while (!leftp->free()) wait(SC_ZERO_TIME);
		if(!temp && up) leftp->test(n, 0);
		else temp = leftp->test(n,0);
		
		busy = false;
		//test_mutex.unlock();
		return temp; // Will this work as intended? :)
		
	// Return value, cause event, unlock mutex.
	
	
}
int Processor::check(){
	return this->unique;
}
void Processor::main()
{
  EoS = 0;
	while(!EoS)
	  {
		// If no unique number has been found yet, try to get a random number.
		if(unique==-1)
		{
		  //cout << name() << " Getting random" << endl;
			// Get random number
			unique = rand() % NR_OF_PROCESSORS; // From 0 - size^2-1
			for(std::vector<int>::iterator it = numbers_in_use.begin(); it!=numbers_in_use.end();++it)
		{
			if(*it == unique)
			{
			  unique = -1;
			}
		}
			if (unique == -1) continue;
			//numbers_in_use.push_back(unique);
			// Test if it is in array
				// TODO : Implement
			// Test up - left
			 wait(SC_ZERO_TIME);
				// TODO: Check if up and left are free before running test...otherwise this will lock.
				// TODO: Other tests should be implemented here in later tasks. Possible #define.
			 if(test(unique, 1))
			{// Up and left thinks unique is available
				// If valid -> store it (do nothing
			  // cout << name() << " Found random= " << unique << endl;
			}
			else
			{
				// Add unique to taken array.
				//cout << name() << " Random taken= " << unique << endl;
				//numbers_in_use.push_back(unique);
				unique = -1;
			}
		}
		// Else do nothing, just wait.
		
		else
		{
		  EoS = 1;// Yield control.
		}
	}
}
#endif /* Task_1 */
#ifdef Task_3
// Constructor
Processor::Processor(sc_module_name processor_name) : sc_module (processor_name)
{
	unique = -1; // Indicates that number has not yet been found.
	busy = 0;
	SC_HAS_PROCESS(Processor);
	SC_THREAD(main);
}

/* Processor::free(void) is used to check if the processor is busy with requests from other
 * Specifically if the processor is currently answering a test(x) from another processor,
 * or have not found it's own unique value yet.
*/
int Processor::free(void)
{
	return !busy;
}

// Returns true if n is found to be in use, and false if n appears to be available.
bool Processor::test(int n)
{
	busy = 1;
	
	cout << "Entered " << name() << "'s test with n= " << n << endl;
	bool temp = true;
	// Perform test:
		// Check if number is my unique number.
		if(n == this->unique)
		{
			busy = 0;
			return false;
		}
		// Check if n is any of the known numbers_in_use.
		for(std::vector<int>::iterator it = numbers_in_use.begin(); it!=numbers_in_use.end();++it)
		{
			if(*it == n)
			{
				busy = 0;
				return false;
			}
		}
		// ALGORITHM:
		// Ask if neighbours know anything about n
		if(rightp->free()==1)
		{ // Keep calling to the right
			temp=rightp->test(n);
		}	
		else if(rightp->free() == -1) // This node is on a right edge
		{
			busy = 0;
			numbers_in_use.push_back(n);
			return true;
		}
		// Left edge - call up and down as well.
		if(leftp->free()==-1) 
		{
			if(upp->free()==1)
				temp=upp->test(n);
			if(downp->free()==1)
				temp=downp->test(n);
		}
		else if(leftp->free() == 1)
		{
			temp = leftp->test(n);
		}
					
		// Number is taken, store it and return false.
		if(temp == false)
		{
			numbers_in_use.push_back(n);
			busy = 0;
			return false;
		}
		else
		{	
			busy = 0;
			numbers_in_use.push_back(n);
			return true; 
		}
}

int Processor::check()
{
	return this->unique;
}
void Processor::main()
{
	cout << name() << " Starting "  << endl;
	bool temp = true;
	int free_temp;
	while(true)
	  {
		 
		// If no unique number has been found yet, try to get a random number.
		if(unique==-1)
		{
			busy = 1;
		  //cout << name() << " Getting random" << endl;
			unique = rand() % NR_OF_PROCESSORS;
			
			// Test if it is in vector of known numbers
			for(std::vector<int>::iterator it = numbers_in_use.begin(); it!=numbers_in_use.end();++it)
			{
				if(*it == unique)
				{
					cout << name() << " Random taken= " << unique << endl;
					unique = -1;
				}
			}
			
			// Number is taken. Restart while loop and get new random number.
			if (unique == -1)	continue; 
			
			// Test to right and left where possible
			if(rightp->free() == 1)
				temp = rightp->test(unique);
			// If on the left edge, also have to test up and down, if  possible.
			if(leftp->free() == 1)
				temp = leftp->test(unique);
			else if(leftp->free() == -1)
			{
				if (upp->free() ==1)
					temp = upp->test(unique);
				if (downp->free() ==1)
					temp = downp->test(unique);
			}
					// Number is taken; add number to vector, restart while loop and get new random number.
			if(temp == false)
			{
				numbers_in_use.push_back(unique);
				cout << name() << " Random taken= " << unique << endl;
				unique = -1;
				continue;
			}
			else
			{
			  cout << name() << " Found random= " << unique << endl;
			  busy = 0;
			  break;
			}
		}
		// Else do nothing, just wait.
		else
		{
			// Yield control by waiting for a delta-cycle.
			wait(SC_ZERO_TIME);
		}
	}
}

#endif /* Task_3 */
